// vim: ft=glsl noet ts=4 sw=4 sts=0
R"vertex(
#version 330 core
smooth out vec2 uv[5];
flat   out vec2 scene_size;
layout(location = 0) in vec2 position;
uniform sampler2D scene;

void main()
{
	gl_Position = vec4(position, 0, 1);
	uv[4] = position*0.5 + 0.5;

	scene_size = textureSize(scene, 0);
	uv[0] = uv[4] + vec2(-1, -1) / scene_size;
	uv[1] = uv[4] + vec2(-1, +1) / scene_size;
	uv[2] = uv[4] + vec2(+1, -1) / scene_size;
	uv[3] = uv[4] + vec2(+1, +1) / scene_size;
}
)vertex"

, /////////////////////////////////////////////////////////////////////////

R"fragment(
#version 330 core
out vec3 color;
smooth in vec2 uv[5];
flat   in vec2 scene_size;
uniform sampler2D scene;

vec3 pixel(sampler2D s, int i) { return texture(s, uv[i]).rgb; }
vec3 pixel(sampler2D s) { return pixel(s, 4); }
vec3 pixel(sampler2D s, vec2 dir, float dist) { return texture(s, uv[4] + dist*dir).rgb; }
vec3 pixel(sampler2D s, vec2 dir, float dist0, float dist1) { return mix(pixel(s, dir, dist0), pixel(s, dir, dist1), 0.5); }

float min5(float a, float b, float c, float d, float e) { return min(a, min(min(b, c), min(d, e))); }
float max5(float a, float b, float c, float d, float e) { return max(a, max(max(b, c), max(d, e))); }
float min_element(vec2 x) { return min(x.x, x.y); }
bool in_range(float x, float a, float b) { return all(lessThan(vec2(a, x), vec2(x, b))); }


const float fxaa_reduce_min = 1.0 / 128.0;
const float fxaa_reduce = 8.0;
const float fxaa_span_max = 8.0;
vec3 fxaa(sampler2D s)
{
	vec3 rgb00 = pixel(s, 0);
	vec3 rgb01 = pixel(s, 1);
	vec3 rgb10 = pixel(s, 2);
	vec3 rgb11 = pixel(s, 3);
	vec3 rgb   = pixel(s, 4);

	const vec3 luma_factor = vec3(0.299, 0.587, 0.114);
	float luma00 = dot(rgb00, luma_factor);
	float luma01 = dot(rgb01, luma_factor);
	float luma10 = dot(rgb10, luma_factor);
	float luma11 = dot(rgb11, luma_factor);
	float luma   = dot(rgb  , luma_factor);
	float luma_min = min5(luma00, luma01, luma10, luma11, luma);
	float luma_max = max5(luma00, luma01, luma10, luma11, luma);
	float luma_avg = (luma00 + luma01 + luma10 + luma11) / 4;

	vec2 dir;
	dir.x = (luma00+luma10) - (luma01+luma11);
	dir.y = (luma00+luma01) - (luma10+luma11);

	float dir_reduce = max(luma_avg / fxaa_reduce, fxaa_reduce_min);
	float rcp_dir_min = min_element(abs(dir)) + dir_reduce;
	dir = clamp(dir / rcp_dir_min, -fxaa_span_max, +fxaa_span_max) / scene_size;

	vec3 rgb0 = pixel(s, dir, 1.0/3.0 - 0.5, 2.0/3.0 - 0.5);
	vec3 rgb1 = mix(rgb0, pixel(s, dir, -0.5, 0.5), 0.5);
	float luma1 = dot(rgb1, luma_factor);

	return mix(rgb0, rgb1, bvec3(in_range(luma1, luma_min, luma_max)));
}


void main()
{
	color = fxaa(scene);
}

)fragment"

